/**
	0	-	full permission
	1	-	can't execute	-	11
	2	-	can't fork		-	2
	3	-	can't read		-	3
	4	-	can't write		-	4
	5	-	can't open		-	5
*/

#include <stdio.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/wait.h>

//#define OS 8 * ORIG_RAX
#define OS 4 * ORIG_EAX
//change your define OS to 4 if your running 32 bit or 8 for 64 bit
//EAX for 32 bit and RAX for 64 bit

//output all system calls made by the child program
//0 = disabled, 1 = enabled
#define showCalls 0

int allowedSetting(int syscall);
int prgSetting=9;
int main(int argc, char *argv[])
{
	int continu=0;
	struct stat sb;
	int status;
	int ax=0;
	//int bx=0;
	char *arguments[argc-1];
	
	
	if (argc>=2)
	{
		if (stat(argv[1], &sb) == -1)
		{
			printf("Error: File does not exist\n");
		}
		else
		{
			//valid path
			continu=1;
		}
	}
	else
	{
		continu=0;
		
		printf("Error: Must supply a path\n");
	}
	
	if (continu==1 && argc>=3 && (strlen(argv[argc-1])==1 
			|| (strlen(argv[argc-1])==2 && atoi(argv[argc-1])==10) ) )
	{
		prgSetting=atoi(argv[argc-1]);
		
		if(prgSetting >= 0 && prgSetting <= 10)
		{
			continu=2;
		}
		else
		{
			printf("Error: Supply a correct setting between 0 - 10\n");
			continu=0;
		}
		
		//additional arguments
		if (prgSetting != (int)argv[2])
		{
			for (status=1; status<argc-1; status++)
			{
				arguments[status-1]=argv[status];
				//printf("Arguments %d = %s\n", status, arguments[status-1]);
			}
			arguments[status-1]=NULL;
			//printf("%d\n", status);
			status=0;
		}
		
	}
	else
	{
		printf("Error: Supply a correct setting between 0 - 10\n");
		continu=0;
	}
	
	if (continu==2)
	{
		//ptrace stuff
		pid_t pID = fork();
		if (pID == 0) {           // child
			ptrace(PTRACE_TRACEME, pID, NULL, NULL);
			//int r= execl(argv[1], strrchr(argv[1], '/')+1, NULL);
			/**	**	**	**	**	**	**	**	**	**/
			int r= execv(argv[1], arguments);
			if(r==0){
				printf("Program begining\n");
			} else if (r==-1){
				printf("Error - could not start program\n");
			}
		} else if (pID < 0) {    // failed to fork
			printf("Failed to create new process\n");
		} else {                 // parent main application
			while (continu==2) {
				wait(&status);
				if(WIFEXITED(status))
				  break;
				//reg_val[1] = ptrace (PTRACE_PEEKUSER, pID, OS, NULL);
				ax = ptrace (PTRACE_PEEKUSER, pID, OS, NULL);
				//bx = ptrace (PTRACE_PEEKUSER, pID, OS + 4, NULL);
				if (!allowedSetting(ax)){
					kill(pID, SIGKILL);
					continu=3;
				}
				
				if (showCalls==1)
					printf("ax = %d\n", ax);
				
		
				ptrace(PTRACE_SYSCALL, pID, NULL, NULL);
				ptrace(PTRACE_SYSCALL, pID, NULL, NULL);
			}
		}
	}
	
	if (continu==3)
	{
		printf("Error: The program attempted to use syscall-%d which it does not have permission to use\n", ax);
	}
	
	return 0;
}

/**
	checks if the current process/syscall is allowed to be executed 
	* by the current program
	
	0=no; 1=yes
 */
int allowedSetting(int syscall)
{
	// No restrictions
	if (prgSetting == 0)
	{
		return 1;
	}
	// Restrict sys_execve
	if (prgSetting == 1)
	{	
		if (syscall==SYS_execve)
		 return 0; 
	}
	// Restrict sys_fork
	if (prgSetting == 2)
	{	
		if (syscall==SYS_fork)
		 return 0; 
	}
	// Restrict sys_read
	if (prgSetting == 3)
	{	
		if (syscall==SYS_read)
		 return 0; 
	}
	// Restrict sys_write
	if (prgSetting == 4)
	{	
		if (syscall==SYS_write)
		 return 0; 
	}
	// Restrict sys_open
	if (prgSetting == 5)
	{	
		if (syscall==SYS_open)
		 return 0; 
	}
	// Restrict sys_execve & sys_fork
	if (prgSetting == 6)
	{	
		if (syscall==SYS_execve || syscall==SYS_fork)
		 return 0; 
	}
	// Restrict sys_read & sys_write
	if (prgSetting == 7)
	{	
		if (syscall==SYS_read || syscall==SYS_write)
		 return 0; 
	}
	// Restrict sys_read, sys_write, & sys_open
	if (prgSetting == 8)
	{	
		if (syscall==SYS_read || syscall==SYS_write || syscall==SYS_open)
		 return 0; 
	}
	// Restrict sys_execve, sys_fork, sys_read, sys_write, & sys_open
	if (prgSetting == 9)
	{	
		if (syscall==SYS_execve || syscall==SYS_fork || syscall==SYS_read || syscall==SYS_write || syscall==SYS_open)
		 return 0; 
	}
	// Only use the five
	if (prgSetting==10)
	{
		if (syscall==SYS_execve || syscall==SYS_fork || syscall==SYS_write || syscall==SYS_open || syscall==SYS_read)
			return 1;
		else
			return 0;
	}

	return 1;
	
}
